package com.dys.hejiayuncommunity.system.service.impl;

import com.dys.hejiayuncommunity.common.constant.UserConstants;
import com.dys.hejiayuncommunity.common.core.domain.TreeSelect;
import com.dys.hejiayuncommunity.common.core.exception.CustomException;
import com.dys.hejiayuncommunity.system.domain.SysDept;
import com.dys.hejiayuncommunity.system.mapper.SysDeptMapper;
import com.dys.hejiayuncommunity.system.service.SysDeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Author: 疾风
 * @ClassName: SysDeptServiceImpl
 * @Description: 部门服务实现类
 * @CreateDate: 2024/12/06
 * @Version: v1.0.0
 */
@Service
public class SysDeptServiceImpl implements SysDeptService {
    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Override
    public List<SysDept> listDepartments(SysDept dept) {
        return sysDeptMapper.selectDeptList(dept);
    }

    @Override
    public SysDept selectDeptById(Long deptId) {
        return sysDeptMapper.selectDeptById(deptId);
    }

    @Override
    public int insertDept(SysDept dept) {
        // 1.获取当前节点的父节点
        SysDept parentDept = sysDeptMapper.selectDeptById(dept.getParentId());

        // 2.父节点异常,则不允许新增子节点
        if (!UserConstants.DEPT_NORMAL.equals(dept.getStatus())) {
            throw new CustomException(500, "部门停用,不允许新增");
        }

        // 3.设置 ancestors 祖级列表字段,记录的是当前节点的所有父节点id
        dept.setAncestors(parentDept.getAncestors() + "," + dept.getParentId());
        return sysDeptMapper.insertDept(dept);
    }

    @Override
    public int updateDept(SysDept dept) {
        // 1.获取父节点
        SysDept newParentDept = sysDeptMapper.selectDeptById(dept.getParentId());

        // 2.获取旧节点数据
        SysDept oldDept = sysDeptMapper.selectDeptById(dept.getDeptId());

        // 3.判断父节点与旧节点是否存在
        if (!Objects.isNull(newParentDept) && !Objects.isNull(oldDept)) {
            // 4.设置最新的祖级列表
            String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
            dept.setAncestors(newAncestors);

            // 5.修改子节点的关系
            String oldAncestors = oldDept.getAncestors();
            updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
        }
        return sysDeptMapper.updateDept(dept);
    }

    /**
     * 修改子元素的关系
     *
     * @param deptId       部门编号
     * @param newAncestors 新的(父id集合)祖级列表
     * @param oldAncestors 旧的(父id集合)祖级列表
     */
    private void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) {
        List<SysDept> childrenList = sysDeptMapper.selectChildrenDeptById(deptId);
        for (SysDept children : childrenList) {
            children.setAncestors(children.getAncestors().replace(oldAncestors, newAncestors));
        }
        if (!childrenList.isEmpty()) {
            sysDeptMapper.updateDeptChildren(childrenList);
        }
    }

    @Override
    public int deleteDeptById(Long deptId) {
        return sysDeptMapper.deleteDeptById(deptId);
    }

    @Override
    public String checkDeptNameUnique(SysDept dept) {
        SysDept deptInfo = sysDeptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());
        if (!Objects.isNull(deptInfo)) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }

    @Override
    public boolean hasChildByDeptId(Long deptId) {
        int result = sysDeptMapper.hasChildByDeptId(deptId);
        return result > 0 ? true : false;
    }

    @Override
    public boolean checkDeptExistUser(Long deptId) {
        int result = sysDeptMapper.checkDeptExistUser(deptId);
        return result > 0 ? true : false;
    }

    @Override
    public List<TreeSelect> buildDeptTreeSelect(List<SysDept> deptList) {
        List<SysDept> deptTrees = buildDeptTree(deptList);
        List<TreeSelect> selectList = deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
        return selectList;
    }

    /**
     * 构建部门树结构
     *
     * @param deptList 部门列表
     * @return 部门树结构
     */
    private List<SysDept> buildDeptTree(List<SysDept> deptList) {
        // 返回的部门列表
        List<SysDept> returnList = new ArrayList<>();

        // 获取所有部门的deptId,保存到List
        List<Long> deptIdList = new ArrayList<>();
        for (SysDept sysDept : deptList) {
            deptIdList.add(sysDept.getDeptId());
        }

        deptList.stream()
                // 如果是顶级节点,遍历该节点下的所有子节点
                .filter(dept -> !deptIdList.contains(dept.getParentId()))
                .forEach(dept -> {
                    // 递归获取子节点
                    recursionFn(deptList, dept);
                    returnList.add(dept);
                });
        return returnList;
    }

    /**
     * 递归遍历节点列表
     *
     * @param deptList 部门列表
     * @param dept     部门信息
     */
    private void recursionFn(List<SysDept> deptList, SysDept dept) {
        // 1.得到子节点
        List<SysDept> childList = getChildDeptList(deptList, dept);
        dept.setChildren(childList);
        for (SysDept childDept : childList) {
            // 2.判断是否还有子节点
            if (hasChild(childList, childDept)) {
                // 递归调用
                recursionFn(deptList, childDept);
            }
        }
    }

    /**
     * 获取子节点列表
     *
     * @param sysDepts 部门列表
     * @param dept     部门信息
     * @return 子节点列表
     */
    private List<SysDept> getChildDeptList(List<SysDept> sysDepts, SysDept dept) {
        List<SysDept> subDeptList = new ArrayList<>();
        subDeptList = sysDepts.stream()
                .filter(subDept -> !Objects.isNull(dept.getParentId()) && subDept.getParentId().longValue() == dept.getDeptId().longValue())
                .collect(Collectors.toList());
        return subDeptList;
    }

    /**
     * 判断是否有子节点
     *
     * @param list      子级部门列表
     * @param childDept 部门列表
     * @return true: 存在, false: 不存在
     */
    private boolean hasChild(List<SysDept> list, SysDept childDept) {
        return !getChildDeptList(list, childDept).isEmpty();
    }
}
